//: \console

import
	tango.io.Stdout,
	tango.io.Console,
	
	Utf	= tango.text.convert.Utf,
	tango.core.Thread,
	
	tango.stdc.string,
	tango.stdc.stringz,
	
	tango.io.device.Array,
	tango.io.device.File,
	tango.io.FilePath,
	
	tango.net.device.Berkeley,
	tango.net.device.Socket,
	tango.net.InternetAddress,
	
	tango.sys.Environment,
	tango.sys.Pipe,
	tango.sys.Process,
	tango.sys.win32.UserGdi,
	tango.sys.win32.WsaSock;

void main() {
	/*
	auto addr	= new InternetAddress("127.0.0.1", 1983);
	ServerSocket ssoc	= new ServerSocket(addr);
	
	while( true ){
		auto soc	= ssoc.accept;
		char[1024] tmp;
		int i	= soc.read(tmp);
		if( i > 0 && i < tmp.length){
			Stdout.formatln("{}", tmp[0..i] );	
		}else{
			Stdout.formatln("{}",i );	
		}
		soc.write("123");
		soc.close;
	}
	return ;
	*/
	
	auto p	= Php.Init(r"D:\usr\local\Apache22\php5_ts\php-cgi.exe");
	p.exec;
	p.wait;

}

struct Php {
	alias Php This ;
	alias typeof(this) pThis ;
	static const MaxLen	= 512 ;
	
	wchar[MaxLen]	dir, app , cmd;
	
	PROCESS_INFORMATION pi ;
	STARTUPINFO si ;
	SECURITY_ATTRIBUTES sa;
	bool	_running ;
	Berkeley	io;
	//Berkeley	err;
	//Pipe		pin ;
	
	static This Init(char[] app, char[] cmd = null ) {
		This	_this ;
		Stdout.formatln("{}", &_this );
		scope path	= new FilePath(app);
		if( !path.exists ){
			return _this ;
		}
		toWDir( _this.dir.ptr , path.parent);
		toWDir( _this.app.ptr , path.toString);
		toWDir( _this.cmd.ptr , cmd);
		
		_this.reset ;

		return _this;
	}
	
	static void toWDir(T)(T* ptr, char[] str){
		tango.stdc.string.memset(ptr, 0,  MaxLen * T.sizeof );
		if( str is null || str.length is 0 ){
			return ;
		}
		T[]	_str	= Utf.fromString8!(T)(str, ptr[0..MaxLen]);
		foreach(ref c; _str){
			if( c is '/' )  c = '\\' ;
		}
	}
	
	void reset() {
		tango.stdc.string.memset(&pi, 0, PROCESS_INFORMATION.sizeof );
		tango.stdc.string.memset(&si, 0, STARTUPINFO.sizeof );
		
		/*
		tango.stdc.string.memset(&sa, 0, SECURITY_ATTRIBUTES.sizeof );
		sa.nLength = SECURITY_ATTRIBUTES.sizeof;
		sa.lpSecurityDescriptor = null;
		sa.bInheritHandle = true;
		*/
		
		si.cb		= STARTUPINFO.sizeof;
		si.dwFlags	= STARTF_USESTDHANDLES;
		
		io.open(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
		
		auto addr	= new InternetAddress("127.0.0.1", 1983);
		io.addressReuse(true);
		io.bind(addr);
		io.listen(32);
		
		/*
		err.open(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
		err.addressReuse(true);
		err.bind(addr);
		err.listen(32);
		*/
		
		si.hStdInput	= cast(HANDLE) io.handle ;
		si.hStdOutput	=  INVALID_HANDLE_VALUE ; 
		si.hStdError		=  INVALID_HANDLE_VALUE ;
		
		/*
		pin			= new Pipe(MaxLen, &sa);
		si.hStdError		= cast(HANDLE) pin.source.fileHandle();
		SetHandleInformation(cast(HANDLE) pin.sink.fileHandle(), HANDLE_FLAG_INHERIT, 0);
		*/
		
		
		_running		= false ;
	}
	
	void exec(){
		char* env_ptr	= null ;
		auto ret	= CreateProcessW(&app[0], &cmd[0], null, null, true, CREATE_NO_WINDOW, env_ptr, &dir[0], &si, &pi ) ;
		if( ret ){
			_running	= true ;
			Stdout.formatln("{}:	{}, pid={}", __LINE__, ret, pi.dwProcessId);
			CloseHandle(pi.hThread);
		}else{
			_running	= false ;
		}
	}
	
	int wait() {
		if (_running) {
			DWORD rc;
			DWORD exitCode;
			scope(exit) {
				CloseHandle(pi.hProcess);
				_running = false;
			}
			rc = WaitForSingleObject(pi.hProcess, INFINITE) ;
			Stdout.formatln("WaitForSingleObject:{}", rc);
			if (rc == WAIT_OBJECT_0) {
				GetExitCodeProcess(pi.hProcess, &exitCode);
				Stdout.formatln("GetExitCodeProcess:{:x}", exitCode);
				return exitCode ;
			} else if (rc == WAIT_FAILED) {
				auto err	= GetLastError();
				Stdout.formatln("GetLastError:{}", err);
			}
		} else {
			
		}
		return 0 ;
	}
}
